package com.summo.demo.config.permissions;

import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSONObject;

import com.summo.demo.config.context.GlobalUserContext;
import com.summo.demo.config.context.UserContext;
import com.summo.demo.config.manager.UserManager;
import com.summo.demo.exception.biz.BizException;
import com.summo.demo.model.response.ResponseCodeEnum;
import com.summo.demo.util.HttpContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@Order(2)
public class RequiresPermissionsHandler {

    @Autowired
    private UserManager userManager;

    @Pointcut("@annotation(com.summo.demo.config.permissions.RequiresPermissions)")
    public void pointcut() {
        // do nothing
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        try {   //获取用户上下文
            UserContext userContext = GlobalUserContext.getUserContext();
            HttpServletResponse httpServletResponse = HttpContextUtil.getHttpServletResponse();
            if (Objects.isNull(userContext)) {
                throw new BizException(ResponseCodeEnum.LOGIN_USER_INFO_CHECK, "用户认证失败，请检查是否登录");
            }
            //获取注解
            MethodSignature signature = (MethodSignature)joinPoint.getSignature();
            Method method = signature.getMethod();
            RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
            //获取当前接口上数据权限
            String[] permissions = requiresPermissions.value();
            if (Objects.isNull(permissions) && permissions.length == 0) {
                throw new BizException(ResponseCodeEnum.LOGIN_USER_INFO_CHECK, "用户认证失败，请检查该接口是否添加了数据权限");
            }
            //判断当前是and还是or
            String[] notHasPermissions;
            switch (requiresPermissions.logical()) {
                case AND:
                    //当逻辑为and时，所有的数据权限必须存在
                    notHasPermissions = checkPermissionsByAnd(userContext.getUserId(), permissions);
                    if (Objects.nonNull(notHasPermissions) && notHasPermissions.length > 0) {
                        throw new BizException(ResponseCodeEnum.NO_PERMISSIONS,
                            MessageFormat.format("用户权限不足，缺失以下权限:[{0}]", JSONObject.toJSONString(notHasPermissions)));
                    }
                    break;
                case OR:
                    //当逻辑为and时，所有的数据权限必须存在
                    notHasPermissions = checkPermissionsByOr(userContext.getUserId(), permissions);
                    if (Objects.nonNull(notHasPermissions) && notHasPermissions.length > 0) {
                        throw new BizException(ResponseCodeEnum.NO_PERMISSIONS,
                            MessageFormat.format("用户权限不足，缺失以下权限:[{0}]", JSONObject.toJSONString(notHasPermissions)));
                    }
                    break;
                default:
                    //默认为and
            }
            return joinPoint.proceed();
        } catch (Exception e) {
            throw e;
        }

    }

    /**
     * 当数据权限为or时，进行判断
     *
     * @param userId      用户ID
     * @param permissions 权限组
     * @return 没有授予的权限
     */
    private String[] checkPermissionsByOr(Long userId, String[] permissions) {
        // 获取用户权限集
        Set<String> permissionSet = userManager.queryAuthByUserId(userId);
        if (permissionSet.isEmpty()) {
            return permissions;
        }
        //一一比对
        List<String> tempPermissions = new ArrayList<>();
        for (String permission1 : permissions) {
            permissionSet.forEach(permission -> {
                if (permission1.equals(permission)) {
                    tempPermissions.add(permission);
                }
            });
        }
        if (Objects.nonNull(tempPermissions) && tempPermissions.size() > 0) {
            return null;
        }
        return permissions;
    }

    /**
     * 当数据权限为and时，进行判断
     *
     * @param userId      用户ID
     * @param permissions 权限组
     * @return 没有授予的权限
     */
    private String[] checkPermissionsByAnd(Long userId, String[] permissions) {
        // 获取用户权限集
        Set<String> permissionSet = userManager.queryAuthByUserId(userId);
        if (permissionSet.isEmpty()) {
            return permissions;
        }
        //如果permissions大小为1，可以单独处理一下
        if (permissionSet.size() == 1 && permissionSet.contains(permissions[0])) {
            return null;
        }
        if (permissionSet.size() == 1 && !permissionSet.contains(permissions[0])) {
            return permissions;
        }
        //一一比对
        List<String> tempPermissions = new ArrayList<>();
        for (String permission1 : permissions) {
            permissionSet.forEach(permission -> {
                if (permission1.equals(permission)) {
                    tempPermissions.add(permission);
                }
            });
        }
        //如果tempPermissions的长度与permissions相同，那么说明权限吻合
        if (permissions.length == tempPermissions.size()) {
            return null;
        }
        //否则取出当前用户没有的权限，并返回用作提示
        List<String> notHasPermissions = Arrays.stream(permissions).filter(
            permission -> !tempPermissions.contains(permission)).collect(Collectors.toList());
        return notHasPermissions.toArray(new String[notHasPermissions.size()]);
    }

}
